/**
 * 
 */
package fileReader.demo.reader;

import java.awt.geom.Point2D;
import java.util.Vector;


/**
 * This is the class were all the main calculations are implemented. The input handling, input
 * transformation, visibility graph force brute construction and Dijkstra execution are placed
 * in this class.
 */
public class VisibilityGraph
{
	
	private Vector polygonList;
	private Vector pointList;
	private Vector obstacleList;
	public Vector edgeList;
	private Vector vertexList;
	private Vector paths;
	public boolean showGraph;
	public boolean showPaths;
	public boolean NoDijkstra;
	
	/**
	 * This method handles the process. When the user wants to trace routes the 
	 * execution comes here.
	 * @param polList polygons
	 * @param controlList vertexes
	 */
    public void InitProcess(Vector polList, Vector controlList)
    {
        polygonList = new Vector();
        pointList = controlList;
        obstacleList = new Vector();
        edgeList = new Vector();
        vertexList = new Vector();
        //int i = polygonList.size();
        
        for(int k=0; k<polList.size(); k++)
        {
        	if( ((DepthArea)polList.get(k)).getMaxDepth()<=Simulator.getSelectedDepth())
        	{
        		polygonList.add(polList.get(k));
        	}
        }
        
        //Scan all the polygons 
        for(int j = 0; j < polygonList.size(); j++)
        {
        	DepthArea polygon_i = (DepthArea)polygonList.get(j);
            int num_vertex = polygon_i.getVertexList().size();

            //FIRST VERTEX! (first and last vertex are special cases!)

            //Create 2 edges with 3 vertexes: i-1,i,i+1
            // Let's turn 2D Points into verteces with better calculation capacity
            
            
            Vertex vprev = new Vertex((Point2D)polygon_i.getVertexList().get(num_vertex - 1), polygon_i);
            Vertex v = new Vertex((Point2D)polygon_i.getVertexList().get(0), polygon_i);
            Vertex vnext = new Vertex((Point2D)polygon_i.getVertexList().get(1), polygon_i);
            
            Edge edge1 = new Edge(vprev, v);
            Edge edge2 = new Edge(v, vnext);
            Edge edge3 = edge1;

            v.SetEdges(edge1, edge2);
            
            //OK, Let's store the new vertex object with the new information about the edges
            vertexList.addElement(v);
            
            obstacleList.addElement(edge1);
            
            //Repeat same operations for all the vertexes
            for(int j1 = 1; j1 < num_vertex - 1; j1++)
            {
                Edge edgei = edge2;
                edge2 = new Edge((Point2D)polygon_i.getVertexList().elementAt(j1), (Point2D)polygon_i.getVertexList().elementAt(j1 + 1));
                v = new Vertex((Point2D)polygon_i.getVertexList().get(j1), polygon_i);
                v.SetEdges(edgei, edge2);
                vertexList.addElement(v);
                obstacleList.addElement(edgei);
            }

            //Last vertex in the polygon!
            v = new Vertex((Point2D)polygon_i.getVertexList().get(num_vertex - 1), polygon_i);
            v.SetEdges(edge2, edge3);
            vertexList.addElement(v);
        }


        //At this point all the polygons are scanned:
        // 		vertexList = CVertex objects of all the polygons with their adjacent edges.
        // 		obstacleList = edges of all the polygons

        //Add control points to vertexList	
        int num_cpoints = pointList.size();
        for(int i1 = 0; i1 < num_cpoints; i1++)
        {
            Vertex v = new Vertex((Point2D)pointList.get(i1), null);
            vertexList.add(v);
        }

	  
        //Time to build Visibility Graph!
        BuildVisibilityGraph();
       
        //Visibility Graph is ready!Minimun condition to start Dijkstra.At least 2 control points!.
        if(num_cpoints >= 2)
        {
           //We will calculate number of paths with Dijkstra to reserve enough memory 
            paths = new Vector((num_cpoints * (num_cpoints - 1)) / 2); //?
            
            //EXECUTE DIJKSTRA'S ALGORITHM!
            Dijkstra();
        }
        
        
        //Clean useless info, we won't need it any more. Adyacent edges in each vertex.
        CleanAdyacencies();
        vertexList.removeAllElements();
    }


	/**
	 *  Build Visibility Graph with brute force         
	 *  checkin the intersection with all the edges.
	 */
    private void BuildVisibilityGraph()
    {
    	 // Scan vertex list to build visibility graph
    	 // Goal: 
    	 //			Get one list of edges belonging to those points which are visibles
    	 //         between them. 
    	 //         Two vertex are visible when there isn't anything between them.
    	 // Solution: 
    	 //			We'll test all the pair of vertes and we'll trace a rule between them and
    	 //         we'll check if this rule intersects with the polygons. If it intersects we won't add
    	 //         it to build our visibility graph.
    	
        for(int i = 0; i < numVerts(); i++)
        {
        	//For each vertex        
            for(int j = 0; j < i; j++)
            {
                Edge cedge = new Edge(vertexAt(i), vertexAt(j));
                
                // Check if edge intersects with each polygon in polygon list
                if(!Intersects(cedge))
                {
                	//We extract the polygon which belongs the vertex
                    DepthArea cpolygon = cedge.getStart().getPolygon();
                    
                    //if cpolygon==null <--- the vertex its a control point: ADD TO VISIBILITY GRAPH
                    //if cpolygon != cedge.end.polygon <-- the two vertexs belong to different polygon: ADD TO VISIBILITY GRAPH
                    //otherwise - two vertex belog to the same polygon we'll check if it's an inner diagonal of the polygon
                    //            : ADD TO VISIBILITY GRAPH if it isn't a inner diagonal

                    if (cpolygon==null || cpolygon != cedge.getEnd().getPolygon() || !cpolygon.IsDiagonal(cedge))
                    {
                    	//Intersect function just checks if 2 edges have intersection in the points which aren't
                    	//the sides of the edge. 
                    	
                    	//Difficult to explain here! See project doc! This was a hard point!
                    	
                    	if(!cedge.isHasColinealPoints()){
                    	  
                    		//Add visible edge to edge list of both vertex i y j
                    		vertexAt(i).SetAdjacent(cedge);
                    		vertexAt(j).SetAdjacent(cedge);
                    		//Add the visible edge to visibility graph list
                    		AddEdge(cedge);
                    	}
                    }
                }
            }

        }

    }
      

   /**
    * Check if this edge intersects with any other
    * edge of the polygons.
    * @param cedge edge
    */
   public boolean Intersects(Edge cedge)
    {
        int i = polygonList.size();
        
        // Scan polygon list
        for(int j = 0; j < i; j++)
        {
            //for each polygon check if the edge intersects with every single side of the polygon
            DepthArea cpolygon = (DepthArea)polygonList.elementAt(j);
            if(cpolygon.Intersects(cedge))
                return true;
        }

        return false;
    }

   /**
    * Calculates optimal paths starting from
    * the first control point.
    */
    public void Dijkstra()
    {
        int num_edges = numEdges();

	    //Scan all the visibility graph and calculate 
        // the cost of every edge related to its lenght.
        for(int i = 0; i < num_edges; i++)
            edgeAt(i).Longitude();

	    
        int num_cpoints = pointList.size();
        
        //Calculate Dijkstra from each control point.
        for(int j = 1; j < num_cpoints; j++)
        {
        	Vertex v = (Vertex)pointList.elementAt(j);
        	
        	System.out.println("CPoint");
            
        	//Initialize Dijkstra's algorithm:
        	//		Create Reminder vector
        	//		Set cost of the nodes to infinity
        	//		Cost of the first node (v) to 0
        	Dijkstra dijkstra = new Dijkstra(this,v);
	         
        	//Calculate Dijkstra's algorithm
        	dijkstra.ComputeAllShortestPaths();
        	//Extract calculated optimal path
        	for(int k = 0; k < j; k++)
            {
             	Vertex destination = (Vertex)pointList.elementAt(k);
               	//from the destination we travel across its predecessors 
             	Path path = dijkstra.ShortestPathTo(destination);
                paths.addElement(path);                   
            }

        }

    }
    
    /**
     * This method resets the cost.
     *
     */
    public void ResetCosts()
    {
        for(int i = 0; i < numVerts(); i++)
        {
        	//Cost = infinite	<-- main condition of dijstra algorithm
            vertexAt(i).setCost(1.7976931348623157E+308D);
            //predecesor none
            vertexAt(i).setPredecessor(null);
        }

    }
    
    /**
     * Removes elements from adyacencies vector.
     *
     */
    public void CleanAdyacencies()
    {
        int i = vertexList.size();
        for(int j = 0; j < i; j++)
        {
            Vertex cvertex = (Vertex)vertexList.elementAt(j);
            cvertex.getAdj().removeAllElements();
        }

    }

    /**
     * Adds edge into edgeList.
     * @param cedge edge to add into list
     */
    private void AddEdge(Edge cedge)
    {
        edgeList.addElement(cedge);
    }

    /**
     * Returns vertexList size
     * @return size
     */
    public int numVerts()
    {
        return vertexList.size();
    }

    /**
     * Returns edgeList size
     * @return size
     */
    private int numEdges()
    {
        return edgeList.size();
    }

    /**
     * Returns a vertex from a certain index.
     * @param i index
     * @return CVertex from vertexList
     */
    public Vertex vertexAt(int i)
    {
        return (Vertex)vertexList.elementAt(i);
    }
    
    /**
     * Returns a edge from a certain index
     * @param i index
     * @return CEdge from edgeList
     */
    private Edge edgeAt(int i)
    {
        return (Edge)edgeList.elementAt(i);
    }

    /**
     * Retruns vertexList.
     * @return vertexList.
     *//*
    public Vector GetVertices()
    {
        return vertexList;
    }*/

    /**
     * Show graph and hide paths.
     *
     */
    public VisibilityGraph()
    {
        showGraph = true;
        showPaths = false;
    }


	public Vector getPaths() {
		return paths;
	}
   
	
}